package com.base.themvx.utils.filetask

import androidx.annotation.WorkerThread
import androidx.lifecycle.MutableLiveData
import com.base.themvx.AppLog
import com.base.themvx.LibApplication
import com.base.themvx.checkOutUrlFileName
import com.base.themvx.defNonSyncLazy
import com.drake.net.Get
import com.drake.net.component.Progress
import com.drake.net.utils.scope
import java.io.File

/**
 ******************(^_^)***********************<br>
 * Author: fee(QQ/WeiXin:1176610771)<br>
 * Date: 2022/8/15<br>
 * Time: 19:18<br>
 * <P>DESC:
 *  通用文件下载器
 * </p>
 * ******************(^_^)***********************
 */
class CommonDownloader private constructor(){

    private val mTag = "CommonDownloader"

    /**
     * 当前下载到的目标文件夹
     */
    private var mTargetFileDir: String = ""

    /**
     * 各下载任务的响应 [MutableLiveData]
     */
    private var mTasksLiveData: MutableLiveData<TaskRespInfo>? = null


    companion object Helper {
        /**
         * 下载的根目录名称
         * def = /download
         */
        private const val ROOT_DIR_NAME = "/download"

        /**
         * 一个默认统一的下载文件夹
         * "data/data/xx.xx.xx/files/download"
         */
        val commonDowloadDir  by defNonSyncLazy {
            val filesDir = LibApplication.sApp.filesDir
            val dirPath = filesDir.absolutePath + ROOT_DIR_NAME
            dirPath
        }

        /**
         * 删除某个文件或者文件夹下的全部文件
         * @param fileOrDirPath 文件或者文件夹完整路径
         */
        @WorkerThread
        fun deleteFile(fileOrDirPath: String) {
            if (fileOrDirPath.isBlank()) {
                return
            }
            val file = File(fileOrDirPath)
            if (file.isFile) {
                file.delete()
            } else if (file.isDirectory) {
                file.list()?.forEach { subFilePath ->
                    deleteFile(subFilePath)
                }
            }
        }

        /**
         * 一个默认统一的下载临时文件夹
         * "data/data/xx.xx.xx/files/temp_download"
         */
        val commonDownloadTempDir by defNonSyncLazy {
            val filesDir = LibApplication.sApp.filesDir
            filesDir.absolutePath + "/temp_download"
        }

        /**
         * 检查指定 目录[dirName] 下的文件 [fileName]是否存在
         * @param dirName String 目录名称(一般为完全路径)
         * @param fileOrDirName String 被检测的文件或者子目录名称
         * @return true: 文件或者文件夹存在; false: 不存在
         */
        fun checkFileExist(dirName: String?, fileOrDirName: String?): Boolean {
            if (dirName.isNullOrBlank() || fileOrDirName.isNullOrBlank()) {
                return false
            }
            val targetFile = File(dirName, fileOrDirName)
            return targetFile.exists() && targetFile.length() > 1
        }

        /**
         * 检测文件是否在统一的下载目录里
         */
        fun checkDownloadFileExist(fileOrDirName: String?): Boolean {
            return checkFileExist(commonDowloadDir, fileOrDirName)
        }

        fun pathOfCommonDownload(fileOrDirName: String) =
            "%s/%s".format(commonDowloadDir, fileOrDirName)

        /**
         * 单例的 下载器
         */
        private val mSingleDownloader by defNonSyncLazy {
            CommonDownloader().apply {
                this.mTargetFileDir = commonDowloadDir
            }
        }

        /**
         * 获取下载器(单例)
         */
        @JvmStatic
        fun getDownloader() = mSingleDownloader

        fun buildDownloadTask(): DownloadTaskInfo {
            return DownloadTaskInfo()
        }

    }

    /**
     * 开始一个下载任务
     * @param theTask DownloadTaskInfo
     */
    fun startDownload(theTask: DownloadTaskInfo?) {
        AppLog.i(mTag,"--> startDownload() theTask = $theTask")
        if (theTask == null) {
            return
        }
        if (theTask.isValidTask()) {
            theTask.let { task ->
                val resUrl = task.mResourceUrl
                //先校验是否目标文件已经存在，可以不用再下载
                var targetFileDir = task.mTargetFileDir
                if (targetFileDir.isBlank()){//下载任务没有指定存储的目录，则使用默认的统一目录
                    targetFileDir = commonDowloadDir
                }
                var finalFileName = task.mFinalFileName
                if (finalFileName.isBlank()){//也没有指定下载的最终保存文件名称，则以 下载 url的文件名
                    //xx.zip / xx.mp3
                    finalFileName = resUrl.checkOutUrlFileName()
                }
                val targetFile = File(targetFileDir,finalFileName)
                if (targetFile.exists() && targetFile.length() > 1){
                    //目标文件已经存在，则不用去下载
                    task.getTaskListener()?.onTaskProgress(true,100,targetFile)
                    mTasksLiveData?.value = TaskRespInfo().apply {
                        this.taskUrl = resUrl
                        this.mErrorInfo = null
                        // TODO:
                    }
                    return@let
                }
                scope{ //该作用域生命周期跟随整个应用
                    val result = Get<File>(resUrl){
//                        val fileFinalName = task.mFinalFileName
//                        if (fileFinalName.isNotBlank()){//默认使用的是 [resUrl]的文件名
//                            setDownloadFileName(fileFinalName)
//                        }
                        val dirFile = File(targetFileDir)
                        if (!dirFile.exists()){//要先创建目录
                            dirFile.mkdirs()
                        }
                        setDownloadDir(targetFileDir)
                        setDownloadFileName(finalFileName)
                        setDownloadFileNameConflict(false)//重名则覆盖
                        //[finalFileName].downloading
                        //删除临时的已下载的文件
                        val tempFilePath = "%s/%s.downloading".format(targetFileDir, finalFileName)
                        deleteFile(tempFilePath)
                        setDownloadTempFile() //使用下载时的临时文件名称
//                        setDownloadMd5Verify()
                        //是否需要下载任务的监听者
                        val isNeedListener =
                            mTasksLiveData != null || task.getTaskListener() != null
                        if (isNeedListener) {
                            val localTaskListener = object : TaskProgressListener() {
                                override fun onProgress(p: Progress) {
                                    task.getTaskListener()?.withError("")?.onProgress(p)
                                    //如果有观察者观察下载任务的响应，则回调响应
                                    mTasksLiveData?.value = TaskRespInfo().apply {
                                        mTaskUrl = resUrl
                                        mProgress = p
                                    }
                                }
                            }
                            localTaskListener.mTaskUrl = resUrl
                            addDownloadListener(localTaskListener)
                        }
                    }.await()
                    task.getTaskListener()?.withError("")?.onTaskProgress(true, 100, result)
                    AppLog.i(mTag, "--> startDownload() task = $task | result = $result")
                }.catch{
                    task.getTaskListener()?.withError(it.message)
                        ?.onTaskProgress(true, 0, null, "$it")
//                    theTask.getTaskListener()?.withError(it.message)?.onProgress(Progress())
                    mTasksLiveData?.value = TaskRespInfo().apply {
                        this.mProgress = null
                        this.taskUrl = resUrl
                        this.mErrorInfo = it.message
                    }
                    AppLog.i(mTag,"--> startDownload() occur: $it")
                }
            }// task.let end
        }//有效的下载资源 end
    }

    /**
     * 外部获取各下载任务的响应 [MutableLiveData],用来观测各下载任务的响应状态
     * 注：由于本对象单例，注意及时注销观察者
     */
    fun getTaskLiveData(): MutableLiveData<TaskRespInfo>? {
        if (mTasksLiveData == null) {
            mTasksLiveData = MutableLiveData()
        }
        return mTasksLiveData
    }
}